# Copyright (c) 2021 Presto Labs Pte. Ltd.
# Author: fengyang

import os
import re
import datetime
from absl import app, flags

from xunkemgmt_client.tool.slack_noti import send_to_slack

FLAGS = flags.FLAGS

log_pattern = r"\[(.*?)\] \[(.*?)\] \[(.*?)\] (.*)"


def check_log_file(file_path):
  # only check the last time fastfeed running
  end = False
  start_time = None
  duration = None
  with open(file_path, 'r') as f:
    for line in f:
      match = re.search(log_pattern, line)
      if match:
        msg = match.group(4)
        time_point = datetime.datetime.strptime(match.group(1), "%Y-%m-%d %H:%M:%S.%f")
        if msg == '=== FastFeed Converter start ===':
          end = False
          start_time = time_point
        elif msg == '=== FastFeed Converter done ===':
          end = True
          duration = time_point - start_time
  return end, duration


def check_log(log_dir, trading_date_str):
  result = []
  log_date_dir = os.path.join(FLAGS.fastfeed_log_dir, trading_date_str)
  assert os.path.exists(log_date_dir), log_date_dir
  not_finished_list = []
  finished_list = []
  for root, machines, files_in_date in os.walk(log_date_dir):
    for machine in machines:
      for machine_dir, dirs_in_machine, files in os.walk(os.path.join(root, machine)):
        for log_file in files:
          full_path = os.path.join(machine_dir, log_file)
          finished, duration = check_log_file(full_path)
          if not finished:
            not_finished_list.append(full_path)
          else:
            finished_list.append((duration, full_path))
  if len(not_finished_list) > 0:
    print("Fastfeed-converter crash, check log:")
    for file_path in not_finished_list:
      print("\t" + file_path)
    result.append("{} fastfeed jobs crash".format(len(not_finished_list)))
  if len(finished_list) > 0:
    print("Duration of fastfeed running")
    storted_finished = sorted(finished_list, reverse=True)
    for index, item in enumerate(storted_finished):
      if index >= 20:
        break
      duration, path = item
      print("\t{}: {}".format(str(duration), path))

  return result


def walk_recipes(fastfeed_dir, trading_date_str):
  results = set()
  machines = os.listdir(fastfeed_dir)
  for m in machines:
    date_dir = os.path.join(fastfeed_dir, m, trading_date_str)
    if not os.path.exists(date_dir):
      continue

    recipes = os.listdir(date_dir)
    for r in recipes:
      compose_recipe = (m, r)
      results.add((compose_recipe))
  return results


def check_recipe(fastfeed_dir, trading_date_str):
  result = []
  trading_date = datetime.datetime.strptime(trading_date_str, "%Y%m%d").date()
  previous_date = trading_date - datetime.timedelta(days=1)
  previous_date_str = previous_date.strftime('%Y%m%d')
  trading_date_recipes = walk_recipes(fastfeed_dir, trading_date_str)
  previous_date_recipes = walk_recipes(fastfeed_dir, previous_date_str)
  gone_recipes = previous_date_recipes - trading_date_recipes
  new_recipes = trading_date_recipes - previous_date_recipes

  if len(gone_recipes) > 0:
    print("Recipe is gone:")
    recipes = list(gone_recipes)
    recipes.sort()
    for comp in recipes:
      print(os.path.join(fastfeed_dir, comp[0], previous_date_str, comp[1]))
    result.append("{} recipes is gone".format(len(gone_recipes)))
  if len(new_recipes) > 0:
    print("Recipe is added:")
    recipes = list(new_recipes)
    recipes.sort()
    for comp in recipes:
      print(os.path.join(fastfeed_dir, comp[0], previous_date_str, comp[1]))
    result.append("{} recipes is added".format(len(gone_recipes)))

  return result


def main(argv):
  trading_date_str = FLAGS.trading_date
  assert trading_date_str, '--trading_date must be specified.'
  result = []
  result.extend(check_recipe(FLAGS.fastfeed_dir, trading_date_str))
  result.extend(check_log(FLAGS.fastfeed_log_dir, trading_date_str))
  if FLAGS.slack_send and len(result) > 0:
    slack_title = "Fastfeed checker " + trading_date_str + '\n'
    mention_list = ['leon', 'fengyang', 'gekim', 'ziyan']
    send_to_slack(slack_title + '\n'.join(result), '#coin_feed_noti', 'msg', mention_list=mention_list)



if __name__ == '__main__':
  flags.DEFINE_string('trading_date', None, 'yyyymmdd')
  flags.DEFINE_string(
      'fastfeed_log_dir',
      '/remote/iosg/jenkins-2/bot-coin/jenkins/workspace/coin2_fastfeed/logs',
      'fastfeed_converter log dir')
  flags.DEFINE_string(
      'fastfeed_dir',
      '/remote/iosg/coin-2/buckets/feed.derived.feed_cache.coin2',
      'fastfeed feed dir')
  flags.DEFINE_boolean('slack_send', False, 'send result to slack')

  app.run(main)
